package com.niren.gatewayservice.config;

import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * \* author: wky
 * \* Date: 2024/11/26
 * \* Time: 16:24
 * \* Project: microservice
 * \* Package: com.niren.gatewayservice.config
 * \* Version: 1.0.0
 * \* To change this template use File | Settings | File Templates.
 * \* Description:请输入源文件描述
 * \
 */
@Component
public class GlobalFilterConfig implements GlobalFilter, Ordered {
    private static final String HEADER_NAME = "Access-Token";

    @Autowired
    RedisTemplate redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("===== 进入拦截器 =====");
        //获取请求对象
        ServerHttpRequest request = exchange.getRequest();
        //获取拦截对象
        ServerHttpResponse response = exchange.getResponse();

        String url = request.getURI().getPath();


        //判断是否为白名单请求，以及一些内置不需要验证的请求。(登录请求也包含其中。)
        //如果当前请求中包含token令牌不为空的时候，也会继续验证Token的合法性，这样能保证
        //Token中的用户信息被业务接口正常访问到了。而如果当Token为空的时候，白名单的接口可以
        //被网关直接转发，无需登录验证。当然被转发的接口，也无法获取到用户的Token身份数据了。
        if(this.shouldNotFilter(url)) {
            return chain.filter(exchange);
        }
        String token = request.getHeaders().getFirst(HEADER_NAME);
        if(StringUtil.isNullOrEmpty(token)) {
            return this.unAuthorize(exchange);
        }
        //查找redis中是否存在Token
        if(!redisTemplate.hasKey("token:" + token)) {
            return this.unAuthorize(exchange);
        }
        //校验Token是否正确，不正确即不放行

        //把新的exchange放回到过滤链
        ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, token).build();
        ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
        return chain.filter(newExchange);
    }

    private boolean shouldNotFilter(String url) {
        /*if(url.startsWith("/user/login")) {
            return true;
        }
        return false;*/
        return true;
    }

    private Mono<Void> unAuthorize(ServerWebExchange exchange) {
        //设置错误状态码为401
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        //设置返回的信息为JSON类型
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
        //自定义错误信息
        String errorMsg = "{\"error\":\"用户未登录或登录超时，请重新登录\"}";
        return exchange.getResponse().writeWith(
                Mono.just(exchange.getResponse().bufferFactory().wrap(errorMsg.getBytes()))
        );
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
